package org.blankie.util;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import org.blankie.lang.Validate;

public class WeakObjectRegistry<I, T extends Identified<I>> implements ObjectRegistry<I, T> {
    
    private final Map<Reference<T>, I> referenceIds = new IdentityHashMap<Reference<T>, I>();
    
    private final Map<I, Reference<T>> registry = new HashMap<I, Reference<T>>();
    
    private final ReferenceQueue<T> queue = new ReferenceQueue<T>();
    
    public WeakObjectRegistry() {
        super();
    }

    @Override
    public T search(I id) {
        expurgeStaleObjects();
        
        Reference<T> reference = registry.get(id);
        return reference == null ? null : reference.get();
    }

    @Override
    public void register(T object) {
        Validate.notNull("object", object);
        
        expurgeStaleObjects();
        
        Reference<T> reference = new WeakReference<T>(object, queue);
        I id = object.getId();
        
        referenceIds.put(reference, id);
        registry.put(id, reference);
    }
    
    private void expurgeStaleObjects() {
        Reference<? extends T> reference = null;
        
        while ((reference = queue.poll()) != null) {
            registry.remove(referenceIds.remove(reference));
        }
    }

}
